import { createObj, PMap, createPMap, PTMap, createPTMap, Weight } from "./utility"


export const MAX_WORD_LENGTH = 512

export interface DictUnit extends Weight {
    word: string
    tag: string
}

export interface Dag  extends Weight{
    nexts: PMap<DictUnit>[],
    pInfo: DictUnit
    runestr: string    
    nextPos: number
}

export interface TrieNode {
    next: PTMap<TrieNode>
    ptValue: DictUnit
}

function createTrieNode():TrieNode{
  return createObj<TrieNode>()
}


let root_: TrieNode

/* @internal */
export interface Trie {
    find(str: string, max_word_len?: number): Dag[]
    getDictUnit(str: string): DictUnit
    insertNode(key: string, ptValue: DictUnit): void
}

/* @internal */
export function createTrie(keys: string[], valuePointers: DictUnit[]): Trie {
    root_ = createTrieNode()
    if (!keys || !valuePointers) {
        return
    }
    if (keys.length !== valuePointers.length) {
        return
    }
    for (let i = 0; i < keys.length; i++) {
        insertNode(keys[i], valuePointers[i])
    }
    return {
        getDictUnit,
        find,
        insertNode,
    }

}

function getDictUnit(word: string): DictUnit {
    if (!word) {
        return
    }
    let ptNode = root_

    for (let i = 0; i < word.length; i++) {
        if (!ptNode.next) {
            return
        }
        let it = ptNode.next[word[i]]
        if (!it) {
            return

        }
        ptNode = it

    }
    return ptNode.ptValue

}

function find(str: string, max_word_len = MAX_WORD_LENGTH): Dag[] {
    if (!root_) {
        throw ("发生错误")
    }
    let res: Dag[] = []
    let ptNode: TrieNode = null

    for (let i = 0; i < str.length; i++) {
        if (!res[i]) {
            res[i] = createObj<Dag>()
        }

        res[i].runestr = str[i]
        let ls = root_.next[res[i].runestr]

        if (root_.next !== null && ls) {
            ptNode = ls
        } else {
            ptNode = null
        }

        let v = createPMap<DictUnit>()
        v.k = i

        if (ptNode === null) {
            v.v = null;
            (res[i].nexts || (res[i].nexts = new Array<PMap<DictUnit>>())).push(v)

        } else {
            v.v = ptNode.ptValue;
            (res[i].nexts || (res[i].nexts = new Array<PMap<DictUnit>>())).push(v)

        }

        for (let j = i + 1; j < str.length && (j - i + 1) <= max_word_len; j++) {
            if (ptNode == null || ptNode.next == null) {
                break
            }
            let ls = ptNode.next[str[j]]
            if (!ls) {
                break
            }
            ptNode = ls

            if (ptNode && ptNode.ptValue) {
                let v = createPMap<DictUnit>()
                v.k = j
                v.v = ptNode.ptValue
                res[i].nexts.push(v)
            }

        }

    }
    return res

}

function insertNode(key: string, ptValue: DictUnit) {

    if (!key) {
        return

    }

    let ptNode: TrieNode = root_

    for (let i = 0, ls; i < key.length; i++) {
        ls = key[i]
        if (!ptNode.next) {
            ptNode.next = createPTMap<TrieNode>()
        }

        if (!ptNode.next[ls]) {

            let nextNode: TrieNode = createTrieNode()
            ptNode.next[ls] = nextNode
            ptNode = nextNode

        }
        else {
            ptNode = ptNode.next[ls]
        }

    }

    if (!ptNode) {
        throw ("发生错误")
    }

    ptNode.ptValue = ptValue

}